/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file nci_task.c
 * @brief NCI任务执行器实现，用于NCI模块执行异步任务
 */

#include "nci_task.h"
#include "message_queue.h"
#include "nfc_log_api.h"

typedef struct {
    volatile bool is_used;
    tMQ_HANDLE handle;
    tMQ_CLEANUP cleanup;
} tNCI_TASK_HANDLE;

// 使用NCI_TASK_EVT_MAX的高字节+1作为数组大小
#define NCI_TASK_HANDLE_SIZE ((NCI_TASK_EVT_MAX >> 8) + 1)

static tMESSAGE_QUEUE s_nci_task = MQ_INIT_VAL("nci_task");
static tNCI_TASK_HANDLE s_task_handles[NCI_TASK_HANDLE_SIZE];

/**
 * @brief NCI任务执行器初始化函数
 *
 * @return 初始化成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nci_task_init() {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    osi_memset_s(s_task_handles, sizeof(tNCI_TASK_HANDLE) * NCI_TASK_HANDLE_SIZE, 0, sizeof(tNCI_TASK_HANDLE) * NCI_TASK_HANDLE_SIZE);
    if (!mq_init(&s_nci_task, NULL, NULL)) {
        NFCLOG_E("NCI_TASK init failed");
        ret = NCI_STATUS_EXT_FAILED;
        goto failed;
    }
    if (!mq_start(&s_nci_task)) {
        NFCLOG_E("NCI_TASK start failed");
        ret = NCI_STATUS_EXT_FAILED;
        goto failed_deinit_mq;
    }
    return NCI_STATUS_OK;
failed_deinit_mq:
    mq_deinit(&s_nci_task);
failed:
    return ret;
}

/**
 * @brief NCI任务执行器销毁函数
 *
 * @return 销毁成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nci_task_deinit() {
    osi_memset_s(s_task_handles, sizeof(tNCI_TASK_HANDLE) * NCI_TASK_HANDLE_SIZE, 0, sizeof(tNCI_TASK_HANDLE) * NCI_TASK_HANDLE_SIZE);
    mq_deinit(&s_nci_task);
    return NCI_STATUS_OK;
}

/**
 * @brief 注册NCI任务
 *
 * @param handle 任务执行器句柄
 * @param cleanup 任务执行器清理函数
 * @param event 需要注册的EVT，选用每个模块的GROUP值进行注册，注册成功后所有此GROUP下的EVT都会分发给handle处理
 *
 * @return 注册成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nci_task_register(tMQ_HANDLE handle, tMQ_CLEANUP cleanup, tNCI_TASK_EVT event) {
    if (!handle) {
        NFCLOG_E("NCI_TASK handle is NULL");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    uint8_t handle_index = (uint8_t)(event >> 8);
    if (handle_index >= NCI_TASK_HANDLE_SIZE) {
        NFCLOG_E("NCI_TASK handle index %d invalid", handle_index);
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (s_task_handles[handle_index].is_used) {
        NFCLOG_W("NCI_TASK handle %d already registered", handle_index);
        return NCI_STATUS_EXT_REJECTED;
    }
    s_task_handles[handle_index].handle = handle;
    s_task_handles[handle_index].cleanup = cleanup;
    s_task_handles[handle_index].is_used = true;
    return NCI_STATUS_OK;
}

/**
 * @brief 注销NCI任务
 *
 * @param num_of_event 本次注销的事件数量
 * @param event 需要注销的EVT，选用每个模块的GROUP值进行注销
 *
 * @return 注销成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nci_task_unregister(tNCI_TASK_EVT event) {
    uint8_t handle_index = (uint8_t)(event >> 8);
    if (handle_index >= NCI_TASK_HANDLE_SIZE) {
        NFCLOG_E("NCI_TASK handle index %d invalid", handle_index);
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (!s_task_handles[handle_index].is_used) {
        NFCLOG_W("NCI_TASK handle %d not registered", handle_index);
        return NCI_STATUS_EXT_REJECTED;
    }
    s_task_handles[handle_index].is_used = false;
    s_task_handles[handle_index].handle = NULL;
    s_task_handles[handle_index].cleanup = NULL;
    return NCI_STATUS_OK;
}

/**
 * @brief 发送NCI任务
 *
 * @note 如果任务发送成功，则会接管args的内存，因此调用者无需再释放
 *
 * @param event 任务事件
 * @param arg1 任务参数1
 * @param arg2 任务参数2
 * @param args 任务参数3
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nci_task_post(tNCI_TASK_EVT event, uint32_t arg1, uint64_t arg2, void *args) {
    return nci_task_post_delay(event, arg1, arg2, args, 0);
}

/**
 * @brief 延时发送NCI任务
 *
 * @note 如果任务发送成功，则会接管args的内存，因此调用者无需再释放
 *
 * @param event 任务事件
 * @param arg1 任务参数1
 * @param arg2 任务参数2
 * @param args 任务参数3
 * @param delay 延时时间
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nci_task_post_delay(tNCI_TASK_EVT event, uint32_t arg1, uint64_t arg2, void *args, uint64_t delay) {
    uint8_t handle_index = (uint8_t)(event >> 8);
    if (handle_index >= NCI_TASK_HANDLE_SIZE) {
        NFCLOG_E("NCI_TASK handle index %d invalid", handle_index);
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_TASK_HANDLE *task_handle = &s_task_handles[handle_index];
    if (!task_handle->is_used) {
        NFCLOG_E("NCI_TASK event %d not registered", handle_index);
        return NCI_STATUS_EXT_REJECTED;
    }
    tMQ_MSG *msg = osi_calloc(sizeof(tMQ_MSG));
    if (!msg) {
        NFCLOG_E("NCI_TASK msg alloc failed");
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    msg->what = event;
    msg->arg1 = arg1;
    msg->arg2 = arg2;
    msg->args = args;
    msg->handle = task_handle->handle;
    msg->cleanup = task_handle->cleanup;
    if (!mq_send_msg_delay(&s_nci_task, msg, delay)) {
        NFCLOG_E("NCI_TASK msg send failed");
        osi_free(msg);
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}
